/**
 * Copyright (c) 2010, iDA MediaFoundry
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * - Neither the name of iDA MediaFoundry nor the names of its contributors may
 *   be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package be.idamf.flash.filesystem
{
	import be.idamf.flash.events.dispatchEventOn;
	import be.idamf.flash.exec.pseudoThreadExec;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.FileListEvent;
	import flash.events.IEventDispatcher;
	import flash.filesystem.File;

	[Event(name="clear", type="flash.events.Event")]
	[Event(name="cancel", type="flash.events.Event")]
	[Event(name="change", type="flash.events.Event")]
	[Event(name="complete", type="flash.events.Event")]

	/**
	 * Performs a file search.
	 * 
	 * @author Maarten Cox
	 * @author Jan Van Coppenolle
	 */
	public class FileSearch extends EventDispatcher implements IFileSearch
	{
		public var processChunk:int = 100;
		public var extension:String;
		public var includeSubDirectories:Boolean;
		public var directory:File;
		
		protected var result:Array;
		protected var isBusy:Boolean;
		protected var dirs:Array;
		protected var files:Array;
		
		public function FileSearch(target:IEventDispatcher = null)
		{
			super(target || this);
		}
		
		public function getResult():Array
		{
			return result;
		}
		
		public function getBusy():Boolean
		{
			return isBusy;
		}
		
		public function execute():void
		{
			if (!directory || !directory.isDirectory)
				throw new Error("No search directory defined");
			
			result = [];
			isBusy = true;
			dirs = [];
			files = [];
			
			dispatchEventOn(this, Event.CLEAR);
			
			parse(directory);
		}
		
		public function cancel():void
		{
			dirs = [];
			files = [];
			
			dispatchEventOn(this, Event.CANCEL);
		}
		
		protected function parse(dir:File):void
		{
			dir.addEventListener(FileListEvent.DIRECTORY_LISTING, directoryListingHandler);
			dir.getDirectoryListingAsync();
		}
		
		protected function directoryListingHandler(event:FileListEvent):void
		{
			File(event.target).removeEventListener(FileListEvent.DIRECTORY_LISTING, directoryListingHandler);
			files = event.files;
			pseudoThreadExec(threadedProcessor);
		}
		
		protected function threadedProcessor():Boolean
		{
			var i:int = processChunk;
			var file:File;
			
			while (--i != 0 && files.length != 0)
			{
				file = files.shift();
				
				if (file.isDirectory)
				{
					if (includeSubDirectories)
						dirs.push(file);
	
					continue;
				}
				
				if (extension && file.type && extension != file.type)
					continue;
					
				result.push(file);
			}
			
			dispatchEventOn(this, Event.CHANGE);
			
			if (files.length != 0)
				return true;
				
			if (dirs.length == 0)
			{
				isBusy = false;				
				dispatchEventOn(this, Event.COMPLETE);
			}
			else
			{
				parse(dirs.shift());
			}

			return false;
		}
	}
}